import random
import re

import logging
from datetime import datetime

from flask import current_app
from flask import make_response, jsonify
from flask import request, json
from flask import session

from info.libs.yuntongxun.sms import CCP
from info.models import User
from info.utils.response_code import RET
from . import passport_blue
from info.utils.captcha.captcha import captcha
from info import redis_store, constants, db


# 获取图像验证码的路由
@passport_blue.route('/image_code')
def get_image_code():
    # 1.获取请求数据中的uuid
    image_code_id = request.args.get('image_code_id')

    # 2.生成验证码，图片
    name, text, image_code = captcha.generate_captcha()
    print(text)

    # 3.保存验证码和id到redis, try:
    try:
        redis_store.set('Image_code_id_' + image_code_id, text, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        # 记录到日志
        current_app.logger.error(e)
        # 返回错误数据给前端
        return make_response(jsonify(errno=RET.DATAERR, errmsg='验证码加载失败'))

    # 4.返回图片
    response = make_response(image_code)
    response.headers['Content-Type'] = 'image/jpg'
    return response


# 获取短信验证码
@passport_blue.route('/sms_code', methods=['POST'])
def get_sms():
    # 1.从url获取参数
    parameter_dict = request.json
    mobile = parameter_dict.get('mobile')
    image_code = parameter_dict.get('image_code')
    image_code_id = parameter_dict.get('image_code_id')

    # 2.判断数据有效性，以及正则匹配手机号格式是否正确
    if not all([mobile, image_code, image_code_id]):
        return make_response(jsonify(errno=RET.PARAMERR, errmsg='参数缺失'))

    if not re.match(r'1[3456789]\d{9}', mobile):
        return make_response(jsonify(errno=RET.PARAMERR, errmsg='手机号有误'))

    # 3.从redis查询验证码text
    try:
        text = redis_store.get('Image_code_id_' + image_code_id)
    except Exception as e:
        # 添加到日志
        current_app.logger.error(e)
        return make_response(jsonify(errno=RET.DBERR, errmsg='查询数据库失败'))
    # 验证码过期
    if not text:
        return make_response(jsonify(errno=RET.NODATA, errmsg='验证码已过期'))

    # 验证码在读取完毕后需要删除，此段逻辑需写在判断验证码是否正确的步奏之前，这样无论是否验证成功，都能删除
    try:
        redis_store.delete('Image_code_id_' + image_code_id)
    except Exception as e:
        current_app.logger.error(e)

    # 4.对比text跟传来的验证码是否一致
    if text.lower() != image_code.lower():
        return make_response(jsonify(errno=RET.DATAERR, errmsg='验证码错误'))

    # 5.创建随机短信验证码，通过第三方发送短信，将这个验证码存储到redis
    # 5.1 需要判断手机号是否已被注册过，注册过就不应该再发送短信，直接返回错误
    try:
        user = User.query.filter_by(mobile=mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询失败')
    if user:
        return jsonify(errno=RET.DATAEXIST, errmsg='该手机号已被注册')

    sms_code_str = '%06d' % random.randint(0, 999999)
    logging.debug('sms_code:%s' % sms_code_str)
    # result = CCP().send_template_sms(mobile, [sms_code_str, 5], 1)
    # if result != 0:
    #     return make_response(jsonify(errno=RET.THIRDERR, errmsg='短信发送失败'))
    try:
        redis_store.set('SMS_' + mobile, sms_code_str, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return make_response(jsonify(errno=RET.DBERR, errmsg='短信验证码存储失败'))

    # 成功了
    return make_response(jsonify(errno=RET.OK, errmsg='短信发送成功'))


# 注册的视图
@passport_blue.route('/register', methods=['POST'])
def register():
    # 1.获取参数
    params_dict = request.json
    mobile = params_dict.get('mobile')
    sms_code = params_dict.get('sms_code')
    password = params_dict.get('password')

    # 2.验证数据有效性，电话符合正则
    if not all([mobile, sms_code, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')
    if not re.match(r'^1[3456789]\d{9}$', mobile):
        return jsonify(errno=RET.DATAERR, errmsg='手机号不符')

    # 3.从redis获取短信验证码
    try:
        real_sms_code = redis_store.get('SMS_' + mobile)
    except Exception as e:
        current_app.logger.debug(e)
        return jsonify(errno=RET.DBERR, errmsg='数据库查询错误')

    # 验证是否过期
    if not real_sms_code:
        return jsonify(errno=RET.NODATA, errmsg='验证码过期')

    # 4.校验验证码是否跟redis中一致
    if real_sms_code != sms_code:
        return jsonify(errno=RET.DATAERR, errmsg='验证码错误')

    # 验证完成删除验证码
    try:
        redis_store.delete('SMS_' + mobile)
    except Exception as e:
        current_app.logger.debug(e)

    # 5.mysql中存储用户注册的信息
    #   1.要查询数据库，该手机号是否已经被注册过了
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据库错误')
    if user:
        return jsonify(errno=RET.DATAEXIST, errmsg='手机号已被注册')

    #   2. 添加到数据库
    user = User()
    user.nick_name = mobile
    user.mobile = mobile
    # 在模型中完成密码加密的工作
    user.password = password

    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        db.session.rollback()
        current_app.logger.error(e)

    # 6.登陆（设置session）
    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile

    # 7.成功返回ok
    return jsonify(errno=RET.OK, errmsg='注册成功')


# 登录
@passport_blue.route('/login', methods=['POST'])
def login():
    # 1.获取参数
    params_dict = request.json
    mobile = params_dict.get('mobile')
    password = params_dict.get('password')

    # 2.数据有效性和电话
    if not all([mobile, password]):
        return jsonify(errno=RET.PARAMERR, errmsg='参数缺失')

    if not re.match(r'1[3456789]\d{9}', mobile):
        return jsonify(errno=RET.PARAMERR, errmsg='手机号格式错误')

    # 3.从数据库查询数据
    try:
        user = User.query.filter_by(mobile=mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg='查询数据库出错')
    if not user:
        return jsonify(errno=RET.NODATA, errmsg='账户还未注册')

    # 4.对比密码
    if not user.check_passowrd(password):
        return jsonify(errno=RET.DATAERR, errmsg='用户名或密码错误')

    # 4.返回登录成功
    session['user_id'] = user.id
    session['nick_name'] = user.nick_name
    session['mobile'] = user.mobile

    # 设置最后登录时间(SQLALCHEMY_COMMIT_ON_TEARDOWN=True配置自动提交)
    user.last_login = datetime.now()

    return jsonify(errno=RET.OK, errmsg='登录成功')


# 退出登录
@passport_blue.route('/logout', methods=['POST'])
def logout():
    session.pop('user_id', None)
    session.pop('nick_name', None)
    session.pop('mobile', None)
    session.pop('is_admin', None)

    return jsonify(errno=RET.OK, errmsg='登出成功')